CSS 阴影
本章节开了新篇,开始学习CSS的阴影。阴影看起来简单,实际上千变万化,能实现很多奇妙的效果。
阴影基础
回顾阴影的基础语法,更多细节可参考 MDN 阴影。
阴影主要分为以下三种:
盒阴影
box-shadow:cssbox-shadow: h-shadow v-shadow blur spread color inset;h-shadow:水平阴影的位置。允许负值。v-shadow:垂直阴影的位置。允许负值。blur:模糊距离。spread:阴影的尺寸。color:阴影的颜色。
文字阴影
text-shadow:csstext-shadow: h-shadow v-shadow blur color;h-shadow:水平阴影的位置。允许负值。v-shadow:垂直阴影的位置。允许负值。blur:模糊距离。color:阴影的颜色。
滤镜阴影
filter: drop-shadow():cssfilter: drop-shadow(h-shadow v-shadow blur color );h-shadow:水平阴影的位置。允许负值。v-shadow:垂直阴影的位置。允许负值。blur:模糊距离。color:阴影的颜色。
三者基本大同小异,box-shadow 有两个特殊性:
box-shadow还能设置内阴影,使用关键字inset进行描述box-shadow多了一个阴影扩散半径的参数
常见阴影
阴影最常见的效果,即最常用的阴影效果:
盒阴影:
cssdiv { box-shadow: 4px 4px 10px 5px rgba(0, 0, 0, 0.5); }
文字阴影:
cssdiv { letter-spacing: 4px; text-shadow: 4px 4px 6px rgba(0, 0, 0, 0.5); }
滤镜阴影:
cssdiv { border: 2px solid orange; filter: drop-shadow(4px 4px 2px #999); }
除了这些常见的阴影,还有很多有趣的阴影效果。
单侧阴影
大多数场景下阴影是两侧或四周都有,如果希望阴影只在一侧,该怎么做?
看回阴影 box-shadow 的语法,举一个例子: box-shadow: 4px 4px 10px 5px #555 ,这四个值分别为:水平偏移、垂直偏移、模糊半径、阴影扩散半径、阴影颜色。
其中,阴影扩散半径是可以设置为负数的!什么意思呢?把阴影的模糊半径和扩散半径设置为相同的值,然后扩散半径设置为负数,这个时候就无法看到盒子的阴影了,因为阴影被盖在盒子下方。
基于此,给阴影添加水平偏移或者垂直偏移,就能看到某个方向的单侧偏移阴影了。
<div class="left">left</div>
<div class="right">right</div>
<div class="top">top</div>
<div class="bottom">bottom</div>div {
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
margin: 30px auto;
border: 1px solid #000;
}
.left {
box-shadow: -7px 0 7px -7px red;
}
.right {
box-shadow: 7px 0 7px -7px red;
}
.top {
box-shadow: 0 -7px 7px -7px red;
}
.bottom {
box-shadow: 0 7px 7px -7px red;
}具体代码可以查看 box-shadow 单侧阴影
立体阴影
立体阴影这个说法很奇怪,毕竟阴影的作用就是让容器显得更有立体感。不过立体阴影并不是使用阴影 box-shadow 来实现立体,而是通过其他元素或者伪类配合样式属性模拟元素的阴影,从而实现立体效果。
来看几个例子做对比:

可以看到,第一个例子就是用的阴影直接实现的,效果不能说美轮美奂,也只能说差强人意。而剩下几个例子,都是通过伪类调整它的布局位置,修改其背景色,最后再设置 box-shadow 添加阴影模糊,来逼真模拟阴影效果。
<div class="box"></div>
<div class="foo"></div>
<div class="both"></div>
<div class="side"></div>.box, .foo, .both, .side {
position: relative;
width: 600px;
height: 100px;
margin: 30px auto;
background: yellow;
border-radius: 10px;
}
.box {
box-shadow: 0 0 10px 2px #555;
}
.foo {
&::before {
content: "";
position: absolute;
top: 50%;
left: 5%;
right: 5%;
bottom: 0;
border-radius: 10px;
background: hsl(48, 100%, 20%);
transform: translate(0, -15%) rotate(-4deg);
transform-origin: center center;
box-shadow: 0 0 20px 15px hsl(48, 100%, 20%);
z-index: -1;
}
}
.both {
background: skyblue;
&::before {
content: "";
position: absolute;
top: 50%;
left: 5%;
right: 5%;
bottom: 15%;
border-radius: 10px;
background: hsl(48, 100%, 20%);
transform: translate(0, -20%) rotate(-4deg);
transform-origin: center center;
box-shadow: 0 0 20px 15px hsl(48, 100%, 20%);
z-index: -1;
}
&::after {
content: "";
position: absolute;
top: 50%;
left: 5%;
right: 5%;
bottom: 15%;
border-radius: 10px;
background: hsl(48, 100%, 20%);
transform: translate(0, -20%) rotate(4deg);
transform-origin: center center;
box-shadow: 0 0 20px 15px hsl(48, 100%, 20%);
z-index: -1;
}
}
.side {
background: pink;
&::before {
content: "";
position: absolute;
top: 15%;
bottom: 20%;
left: 90%;
right: 5%;
border-radius: 10px;
background: hsl(150, 62%, 20%);
transform: translate(105%, 10%) rotate(15deg);
transform-origin: center center;
box-shadow: 0 0 10px 7px hsl(150, 62%, 20%);
z-index: -1;
}
&::after {
content: "";
position: absolute;
top: 15%;
bottom: 20%;
left: 5%;
right: 90%;
border-radius: 10px;
background: hsl(150, 62%, 20%);
transform: translate(-105%, 10%) rotate(-15deg);
transform-origin: center center;
box-shadow: 0 0 10px 7px hsl(150, 62%, 20%);
z-index: -1;
}
}具体原理也很简单,伪类再背后的叠加形成,如下图所示:

具体代码可以查看 立体阴影
浮雕阴影
浮雕阴影的本质还是 box-shadow 和 text-shadow,只是需要控制好颜色的配合以及内外阴影的一起使用。核心有两点:
- 背景色与内容(文本或者盒子颜色)一致
- 使用两个相反的方向,使用两组对比明显的颜色值,来实现凹凸效果
来看看这两个效果的图:

这两个是全然相反的浮雕阴影效果,一个是凹一个是凸。只需要修改字体阴影色值就能实现相反的效果。
<div class="out">Daodao</div>
<div class="in">Daodao</div>body {
width: 100vw;
height: 100vh;
text-align: center;
background: #999;
}
div {
font-size: 105px;
font-weight: bold;
color: #999;
}
.out {
text-shadow: 1px 1px 1px #000, -1px 1px 1px #fff;
}
.in {
text-shadow: 1px 1px 1px #fff, -1px 1px 1px #000;
}具体代码可以查看 浮雕阴影
新拟态风格阴影
上一个浮雕阴影是针对文字做的,而新拟态风格阴影则是针对盒子的,这种风格一般用于扁平化设计,让元素看起来有立体感。
和浮雕阴影的原理类似,也是使用相反的方向和对比明显的色值,来实现盒子的凹凸效果。还能把他们的值在 active 后取反,实现点击动画效果。
div {
width: 100px;
height: 100px;
margin: 30px auto;
background: #e9ecef;
text-align: center;
line-height: 100px;
cursor: pointer;
transition: all 0.2s;
box-shadow: 7px 7px 12px rgba(0, 0, 0, 0.4),
-7px -7px 12px rgba(255, 255, 255, 0.9),
inset 0 0 0 rgba(255, 255, 255, 0.9), inset 0 0 0 rgba(0, 0, 0, 0.4);
}
div:active {
box-shadow: 0 0 0 rgba(0, 0, 0, 0.4), 0 0 0 rgba(255, 255, 255, 0.9),
inset -7px -7px 12px rgba(255, 255, 255, 0.9),
inset 7px 7px 12px rgba(0, 0, 0, 0.4);
}具体代码可以查看 新拟态风格阴影
长阴影(长投影)
顾名思义,就是用阴影搭配 transform 和渐变,实现模拟投影的效果。主要的实现思路是:
- 为盒子容器添加
::before和::after伪类,添加position为absolute绝对定位 before伪类调整中心点为左中,然后整体平移到右边,基于 Y 轴倾斜角度,缩放元素调整一下大小after伪类调整中心点为上中,然后整体平移到底部,基于 X 轴倾斜角度,缩放元素调整一下大小
关键点就在于 transform 的使用,如 transform-origin 设置中心点、 skew 倾斜角度、 scale 缩放元素大小。
body {
background: linear-gradient(90deg, hsl(199, 98%, 50%), hsl(199, 98%, 38%));
overflow: hidden;
}
div {
position: relative;
width: 30vmin;
height: 30vmin;
background: #fff;
margin: 30vmin auto;
}
div::before,
div::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
}
div::before {
transform-origin: 0 50%;
transform: translate(100%, 0) skewY(45deg) scaleX(.6);
background: linear-gradient(90deg, rgba(0, 0, 0, .3), transparent);
animation: shadowMoveY 5s infinite linear alternate;
}
div::after {
transform-origin: 0 0;
transform: translate(0%, 100%) skewX(45deg) scaleY(.6);
background: linear-gradient(180deg, rgba(0, 0, 0, .3), transparent);
animation: shadowMoveX 5s infinite linear alternate;
}
@keyframes shadowMoveX {
to {
transform: translate(0%, 100%) skewX(50deg) scaleY(.6);
}
}
@keyframes shadowMoveY {
to {
transform: translate(100%, 0) skewY(40deg) scaleX(.6);
}
}
具体代码可以查看 线性渐变模拟长阴影
彩色阴影 / 渐变阴影
box-shadow 一般都是实现单色阴影,如果想要实现彩色或渐变阴影,也可以使用其他的方法。
在CSS中,最常见的彩色阴影实现方式是通过 filter: blur() 模糊滤镜来把同样颜色的副本模糊化模拟阴影效果。对应的,副本则需要使用 background: inherit 继承父元素的背景色,这样模糊后的阴影颜色和父元素一致。
div {
position: relative;
width: 100px;
height: 100px;
background: url(.....) no-repeat center center;
}
div::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: inherit;
filter: blur(10px) brightness(80%) opacity(.8);
z-index: -1;
}此方法的步骤如下:
- 利用元素的伪元素,生成了一个与原图一样的新图,并且将其叠加在原图之下
- 利用滤镜
filter: blur()配合其他的亮度、对比度、透明度等滤镜,制作出与原图类似的虚幻的影子,伪装成原图的阴影效果
同样的,还可以用这个方法实现渐变边框阴影,效果如下图所示:

实际上也是做一个锥形渐变。
div {
background-image: conic-gradient(#ff4d00, #ffe600, #80ff00, #00ff1a, #00ffb3, #00b3ff, #001aff, #8000ff, #ff00e6, #ff004d 20%, transparent 20.5%, transparent
);
}
然后添加模糊滤镜。
div {
background-image: conic-gradient(#ff4d00, #ffe600, #80ff00, #00ff1a, #00ffb3, #00b3ff, #001aff, #8000ff, #ff00e6, #ff004d 20%, transparent 20.5%, transparent
);
filter: blur(10px);
}
然后在上面覆盖一个和背景色一样的、比整体盒子小 1、2 像素的盒子,把中间部分遮挡住,这样就能实现渐变边框阴影效果。
或者设置伪类的背景色为锥形渐变,宽度通过计算属性 calc(100% + 12px) 多设置 12 像素,然后通过 left: -6px 和 top: -6px 调整位置模拟边框,这样也能实现渐变边框阴影效果。

总结
阴影是非常实用的一个属性,通过它可以实现很多效果,如阴影、浮雕、拟态、长投影等。
- 阴影主要类型包括
box-shadow(盒阴影)、text-shadow(文字阴影)和filter: drop-shadow()(滤镜阴影),它们语法相似但各有特点,如box-shadow可设置内阴影和扩散半径。 - 通过巧妙运用
box-shadow的偏移、模糊、扩散等参数,可以实现单侧阴影、立体阴影、浮雕阴影、新拟态风格阴影、长阴影及彩色/渐变阴影等多种视觉效果。 - 实现这些效果常用技巧包括:利用负的扩散半径创造单侧阴影;结合伪元素和
transform模拟立体感;通过反向阴影色值实现浮雕凹凸;使用多层box-shadow或filter结合background继承模拟复杂阴影与渐变效果。